#pragma once

/**
 * @file matching_engine.h
 * @brief 匹配引擎定义
 *
 * 本文件定义了交易所的核心组件匹配引擎（MatchingEngine）。
 * 匹配引擎负责接收客户端请求，处理订单的添加和取消，
 * 执行订单撤合，并生成客户端响应和市场数据更新。
 * 它是交易所系统的核心组件，负责维护订单簿并执行交易撤合。
 *
 * @author 原作者
 * @date 未知
 */

#include "common/thread_utils.h"
#include "common/lf_queue.h"
#include "common/macros.h"

#include "order_server/client_request.h"
#include "order_server/client_response.h"
#include "market_data/market_update.h"

#include "me_order_book.h"

namespace Exchange {
  /**
   * @brief 匹配引擎类
   * 
   * 匹配引擎是交易所系统的核心组件，负责处理订单并执行撤合。
   * 它维护多个交易品种的订单簿，处理订单的添加和取消操作，
   * 并根据价格-时间优先原则执行订单撤合。
   * 
   * 匹配引擎通过无锁队列与订单服务器和市场数据发布器进行通信，
   * 确保高效的数据交换和低延迟的处理。
   */
  class MatchingEngine final {
  public:
    /**
     * @brief 构造函数
     * 
     * 创建匹配引擎实例，初始化内部数据结构和连接无锁队列。
     * 
     * @param client_requests 客户端请求无锁队列指针，用于接收来自订单服务器的请求
     * @param client_responses 客户端响应无锁队列指针，用于发送响应给订单服务器
     * @param market_updates 市场数据更新无锁队列指针，用于发送市场数据更新给市场数据发布器
     */
    MatchingEngine(ClientRequestLFQueue *client_requests,
                   ClientResponseLFQueue *client_responses,
                   MEMarketUpdateLFQueue *market_updates);

    /**
     * @brief 析构函数
     * 
     * 清理匹配引擎资源，停止匹配引擎线程，并释放所有订单簿。
     */
    ~MatchingEngine();

    /**
     * @brief 启动匹配引擎主线程
     * 
     * 创建并启动匹配引擎的主线程，开始处理客户端请求。
     */
    auto start() -> void;

    /**
     * @brief 停止匹配引擎主线程
     * 
     * 通过设置运行标志为false来停止匹配引擎的主线程。
     */
    auto stop() -> void;

    /**
     * @brief 处理客户端请求
     * 
     * 处理从无锁队列中读取的客户端请求，根据请求类型执行相应的操作。
     * 支持的操作包括添加新订单和取消现有订单。
     * 如果收到无效的请求类型，将会触发致命错误。
     * 
     * @param client_request 客户端请求指针，包含请求的详细信息
     */
    auto processClientRequest(const MEClientRequest *client_request) noexcept {
      // 获取相应交易品种的订单簿
      auto order_book = ticker_order_book_[client_request->ticker_id_];
      // 根据请求类型执行不同的操作
      switch (client_request->type_) {
        case ClientRequestType::NEW: { // 处理新订单请求
          START_MEASURE(Exchange_MEOrderBook_add); // 开始性能计时
          // 将新订单添加到订单簿中
          order_book->add(client_request->client_id_, client_request->order_id_, client_request->ticker_id_,
                           client_request->side_, client_request->price_, client_request->qty_);
          END_MEASURE(Exchange_MEOrderBook_add, logger_); // 结束性能计时并记录
        }
          break;

        case ClientRequestType::CANCEL: { // 处理取消订单请求
          START_MEASURE(Exchange_MEOrderBook_cancel); // 开始性能计时
          // 从订单簿中取消订单
          order_book->cancel(client_request->client_id_, client_request->order_id_, client_request->ticker_id_);
          END_MEASURE(Exchange_MEOrderBook_cancel, logger_); // 结束性能计时并记录
        }
          break;

        default: { // 处理无效的请求类型
          // 触发致命错误，记录无效的请求类型
          FATAL("Received invalid client-request-type:" + clientRequestTypeToString(client_request->type_));
        }
          break;
      }
    }

    /**
     * @brief 将客户端响应写入无锁队列
     * 
     * 将客户端响应写入无锁队列，供订单服务器消费。
     * 该方法首先记录日志，然后获取队列中的下一个可写位置，
     * 将客户端响应移动到该位置，并更新队列的写入索引。
     * 
     * @param client_response 要发送的客户端响应指针
     */
    auto sendClientResponse(const MEClientResponse *client_response) noexcept {
      // 记录发送客户端响应的日志
      logger_.log("%:% %() % Sending %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_), client_response->toString());
      // 获取无锁队列中的下一个可写位置
      auto next_write = outgoing_ogw_responses_->getNextToWriteTo();
      // 将客户端响应移动到队列中
      *next_write = std::move(*client_response);
      // 更新队列的写入索引
      outgoing_ogw_responses_->updateWriteIndex();
      // 记录写入队列的性能指标
      TTT_MEASURE(T4t_MatchingEngine_LFQueue_write, logger_);
    }

    /**
     * @brief 将市场数据更新写入无锁队列
     * 
     * 将市场数据更新写入无锁队列，供市场数据发布器消费。
     * 该方法首先记录日志，然后获取队列中的下一个可写位置，
     * 将市场数据更新复制到该位置，并更新队列的写入索引。
     * 
     * @param market_update 要发送的市场数据更新指针
     */
    auto sendMarketUpdate(const MEMarketUpdate *market_update) noexcept {
      // 记录发送市场数据更新的日志
      logger_.log("%:% %() % Sending %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_), market_update->toString());
      // 获取无锁队列中的下一个可写位置
      auto next_write = outgoing_md_updates_->getNextToWriteTo();
      // 将市场数据更新复制到队列中
      *next_write = *market_update;
      // 更新队列的写入索引
      outgoing_md_updates_->updateWriteIndex();
      // 记录写入队列的性能指标
      TTT_MEASURE(T4_MatchingEngine_LFQueue_write, logger_);
    }

    /**
     * @brief 匹配引擎的主循环
     * 
     * 匹配引擎线程的主循环，不断处理从无锁队列中读取的客户端请求。
     * 对于每个请求，调用processClientRequest方法进行处理，
     * 这会生成相应的客户端响应和市场数据更新。
     * 当run_标志为false时，循环结束。
     */
    auto run() noexcept {
      // 记录匹配引擎启动的日志
      logger_.log("%:% %() %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_));
      // 主循环，当run_为true时持续运行
      while (run_) {
        // 从无锁队列中获取下一个要读取的客户端请求
        const auto me_client_request = incoming_requests_->getNextToRead();
        // 如果有可读取的请求
        if (LIKELY(me_client_request)) {
          // 记录从队列读取的性能指标
          TTT_MEASURE(T3_MatchingEngine_LFQueue_read, logger_);

          // 记录处理请求的日志
          logger_.log("%:% %() % Processing %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_),
                      me_client_request->toString());
          // 开始性能计时
          START_MEASURE(Exchange_MatchingEngine_processClientRequest);
          // 处理客户端请求
          processClientRequest(me_client_request);
          // 结束性能计时并记录
          END_MEASURE(Exchange_MatchingEngine_processClientRequest, logger_);
          // 更新队列的读取索引
          incoming_requests_->updateReadIndex();
        }
      }
    }

    /// Deleted default, copy & move constructors and assignment-operators.
    MatchingEngine() = delete;

    MatchingEngine(const MatchingEngine &) = delete;

    MatchingEngine(const MatchingEngine &&) = delete;

    MatchingEngine &operator=(const MatchingEngine &) = delete;

    MatchingEngine &operator=(const MatchingEngine &&) = delete;

  private:
    /**
     * @brief 交易品种到订单簿的映射
     * 
     * 哈希映射容器，将交易品种ID映射到相应的订单簿对象。
     * 每个交易品种都有一个独立的订单簿来管理其订单和执行撤合。
     */
    OrderBookHashMap ticker_order_book_;

    /**
     * @brief 无锁队列指针
     * 
     * 这些无锁队列用于与其他组件进行高效的数据交换：
     * - incoming_requests_: 用于消费订单服务器发送的客户端请求
     * - outgoing_ogw_responses_: 用于发布客户端响应，由订单服务器消费
     * - outgoing_md_updates_: 用于发布市场数据更新，由市场数据发布器消费
     */
    ClientRequestLFQueue *incoming_requests_ = nullptr;     ///< 订单服务器发送的客户端请求队列
    ClientResponseLFQueue *outgoing_ogw_responses_ = nullptr; ///< 发送给订单服务器的客户端响应队列
    MEMarketUpdateLFQueue *outgoing_md_updates_ = nullptr;  ///< 发送给市场数据发布器的市场数据更新队列

    /**
     * @brief 运行标志
     * 
     * 控制匹配引擎主循环是否继续运行的标志。
     * 当设置为false时，匹配引擎的主循环将结束。
     */
    volatile bool run_ = false;

    std::string time_str_;  ///< 用于日志记录的时间字符串缓冲区
    Logger logger_;        ///< 日志记录器，用于记录匹配引擎的操作和状态
  };
}
